/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package server;

import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Handles one HTTP request
 * @author Peewhy
 */
public class HttpThread implements Runnable {
    private Socket connectionSocket;
    private Server server;
    public static int id = 0;
    private int threadId = id;
    private Logger logger;
    
    /**
     * Counts how many instances created, and assigns id (static var)
     * @param s reference to server
     * @param cs socket, for which connection with client was established
     */
    public HttpThread(Server s, Socket cs) {
        this.connectionSocket = cs;
        this.server = s;
        HttpThread.id = HttpThread.id + 1;
        this.threadId = HttpThread.id;
        this.logger = Logger.getLogger(Server.LOG);
    }
    
    /**
     * handles HTTP request.
     * 1. Creates input stream
     * 2. Creates output stream
     * 3. Reads and parses request header
     * 4. Send respond back to client
     */
    public void run() {
        // Open input stream
        InputStream conInputStream;
        InputStreamReader conStreamReader;
        BufferedReader inFromClient;                
        try  {
            conInputStream = connectionSocket.getInputStream();
            conStreamReader = new InputStreamReader(conInputStream);
            inFromClient = new BufferedReader(conStreamReader);
        }
        catch (IOException io) {
            logger.log(Level.SEVERE, "Cannot create input strem for request #" + threadId);
            return;
        }

        // Open output Stream
        OutputStream outputStream;
        DataOutputStream dataOutputStream;
        DataOutputStream outToClient;
        try {
            outputStream = connectionSocket.getOutputStream();
            dataOutputStream = new DataOutputStream(outputStream);                
            outToClient = new DataOutputStream(dataOutputStream);
        }
        catch (IOException io2) {
            logger.log(Level.SEVERE, "Cannot create output stream for request #" + threadId);
            return;                    
        }

        Request request = new Request();
        Response response = new Response(server, request);


        boolean requestParsed = true;
        String line;
        try {
            line = inFromClient.readLine();                    
            request.parseFirstLine(line);
        }
        catch (Exception ie) {
            // First header line is corrupted
            logger.log(Level.INFO, "First request header line corrupted: " + ie.getMessage());
            response.header.setStatus(400);
            requestParsed = false;
        }
                
        line = "";
        boolean emptyLine = false;
        try {
            while (inFromClient.ready() && (!emptyLine)) {
                try {
                    line = inFromClient.readLine();
                    request.parseLine(line);
                    if (line.length() <= 0) {
                    	emptyLine = true;
                    }
                }
                catch (Exception err) {
                    logger.log(Level.INFO, "Request header line corrupted");                        
                } 
            }
            logger.log(Level.INFO, "Finished parsing request");

            if (inFromClient.ready()) {            
            	char[] cbuf = new char[20000];                                    
                int bread = inFromClient.read(cbuf);                        
                String bb = (new String(cbuf)).substring(0, bread);
                request.addPostDataLine(bb);            
            }
            /*
            while (inFromClient.ready()) {            	
            	line = inFromClient.readLine();
            	
            	request.addPostDataLine(line);
            } 
            */       
        }
        catch (IOException er) {
        	logger.log(Level.SEVERE, er.getMessage());
        } // Not Expected
        catch (Exception ee) {
        	logger.log(Level.SEVERE, ee.getMessage());
        } // Not Expected
                        
        request.parsePostData();
        request.parseGetData();        
        
        // If Request headers are OK
        if (requestParsed) {
            try {
                response.handle();
            }
            catch (IOException e) {
               logger.log(Level.SEVERE, "Cannot respiond to the request");
            }
            catch (Exception e) {
            	logger.log(Level.SEVERE, e.getLocalizedMessage());            	
            }
        }
        else {
            response.header.setStatus(404);
        }

        // Send generated response back to the User.
        try {        	
            response.show(outToClient);
        }
        catch (IOException ior) {
            logger.log(Level.SEVERE, "Error while sending respond to client");
            return;
        }

        // Closing a conenction    
        try {       
            outToClient.close();
        }
        catch (IOException ior) {
            logger.log(Level.SEVERE, "Error while closing connection");
            return;
        }

    } // 
}
